//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - SaaS Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================


//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - S+S Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Text;
using System.IO;
using System.Net;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;

using LitwareHR.PublicApp.WinUX.Properties;
using Shp.Runtime.Contract;

using Microsoft.Practices.CompositeUI;
using Microsoft.Practices.ObjectBuilder;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.Data.SqlCe;
using System.ComponentModel;
using System.Threading;
using Microsoft.Practices.SmartClient.ConnectionMonitor;
using Microsoft.Practices.CompositeUI.Utility;
using Microsoft.Practices.CompositeUI.EventBroker;
using System.Diagnostics;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using LitwareHR.PublicApp.WinUX.Constants;
using System.Drawing;
using System.Windows.Media.Imaging;
using LitwareHR.Infrastructure.Interface.Constants;
using System.Globalization;

namespace LitwareHR.PublicApp.WinUX.Services
{
    /// <summary>
    /// This service encapsulates Litware tenant branding (currently just the Logo on the banner)
    /// </summary>
    public class TenantBrandingService: IDisposable  
    {
        /// <summary>
        /// Used to describe the payload of the asynch call 
        /// </summary>
        class ImageDownloadInfo
        {
            public string filePath;
            public string cssStyle;

            public ImageDownloadInfo(string _filePath, string _cssStyle)
            {
                filePath = _filePath;
                cssStyle = _cssStyle;
            }
        }

        [EventPublication(EventTopicNames.NewLogo, PublicationScope.Global)]
        public event EventHandler<DataEventArgs<Bitmap>> NewTenantLogo;

        [EventPublication(EventTopicNames.NewLogoProgress, PublicationScope.Global)]
        public event EventHandler<DataEventArgs<int>> NewTenantLogoProgress;

        private ServiceProxy.UnSecure.PresentationService presentationService = null;
        private ConnectionMonitor connectionMonitorService = null;
        private AuthenticationService authenticationService = null;
        private Timer timer;
        private string _currentStyle;
        private WebClient web = null;

        [InjectionConstructor]
        public TenantBrandingService([ServiceDependency] ServiceProxy.UnSecure.PresentationService presentationService,
                                     [ServiceDependency] ConnectionMonitor connectionMonitorService,
                                     [ServiceDependency] AuthenticationService authenticationService )
        {
            this.presentationService = presentationService;
            this.connectionMonitorService = connectionMonitorService;
            this.authenticationService = authenticationService;

            _currentStyle = Properties.Settings.Default.CurrentStyle;
            
            //WebClient is used to download the image
            web = new WebClient();
            web.DownloadFileCompleted += new AsyncCompletedEventHandler(web_DownloadFileCompleted);
            web.DownloadProgressChanged += new DownloadProgressChangedEventHandler(web_DownloadProgressChanged);

        }

        public void Initialize()
        {
            // Setup the "timer to get automatic updates on the Logo
            timer = new Timer(new TimerCallback(GetTenantLogoTimerCallback), null, 0, 2000);
        }

        /// <summary>
        /// Timer callback
        /// </summary>
        /// <param name="o"></param>
        private void GetTenantLogoTimerCallback(object o)
        {
            // If a request is already in progress or the client is offline, notify the last valid Logo
            if(web.IsBusy || !connectionMonitorService.IsConnected)
            {
                if (!String.IsNullOrEmpty(Properties.Settings.Default.LogoPath))
                    FireNewLogoEvent(Properties.Settings.Default.LogoPath);
            }
            else
            {
                DownloadLogo();
            }
        }

        /// <summary>
        /// Get the notification as is (from whatever is stored locally).
        /// </summary>
        public void GetTenantLogo()
        {
            if (!String.IsNullOrEmpty(Properties.Settings.Default.LogoPath))
            {
                FireNewLogoEvent(Properties.Settings.Default.LogoPath);
            }
            else
            {
                GetTenantLogoTimerCallback(null);
            }
        }

        private void DownloadLogo()
        {
            try
            {
                // Get the currently configured style from LitwareHR
                string cssUrl = presentationService.GetConfiguredStyle(authenticationService.CurrentTenantAlias);

                // No changes, exit silently.
                if (_currentStyle == cssUrl)
                {
                    return;
                }

                string imgUrl = GetImageUrl(cssUrl);
                string filePath = string.Format(CultureInfo.InvariantCulture, "{0}{1}-{2}{3}", AppDomain.CurrentDomain.BaseDirectory, @"Logo", Guid.NewGuid().ToString(), imgUrl.Substring(imgUrl.LastIndexOf(".", StringComparison.InvariantCulture)));
                web.DownloadFileAsync( new Uri( imgUrl ), filePath, new ImageDownloadInfo( filePath, cssUrl) );
            }
            catch (WebException ex)
            {
                ExceptionPolicy.HandleException(ex, "Default Policy");
            }
            catch (InvalidOperationException ex)
            {
                ExceptionPolicy.HandleException(ex, "Default Policy");
            }
            catch( Exception ex )
            {
                ExceptionPolicy.HandleException(ex, "Default Policy");
             //   throw;
            }
        }

        /// <summary>
        /// Progress report callback from WebClient call (used to download the image)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void web_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            int percentage = (int) ((e.BytesReceived * 100) / e.TotalBytesToReceive);
            NewTenantLogoProgress(this, new DataEventArgs<int>(percentage));
        }

        private void FireNewLogoEvent(string logoFile)
        {
            if (File.Exists(logoFile))
            {
                Bitmap image = new Bitmap(logoFile);
                NewTenantLogo(this, new DataEventArgs<Bitmap>(image));
            }
        }

        /// <summary>
        /// Callback when download of the image is complete
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void web_DownloadFileCompleted(object sender, AsyncCompletedEventArgs args)
        {
            if (args.Error != null)
            {
                ExceptionPolicy.HandleException(args.Error, "Default Policy");
                return;
            }

            ImageDownloadInfo imgInfo = (ImageDownloadInfo) args.UserState;
            Properties.Settings.Default.LogoPath = imgInfo.filePath;
            Properties.Settings.Default.CurrentStyle = _currentStyle = imgInfo.cssStyle;
            Properties.Settings.Default.Save();
            FireNewLogoEvent(imgInfo.filePath);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        /// 
        private static Stream GetResponse(string url)
        {
            //Create a HTTPWebRequest Object
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

            //Apply credentials
            request.Credentials = CredentialCache.DefaultCredentials;
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            //Get the CSS file from the response.
            Stream result = response.GetResponseStream();

            return result;
        }

        /// <summary>
        /// Extracts the URL of the image for the configured CSS page (currently in use in the Tenant's 
        /// UI options)
        /// </summary>
        /// <param name="cssUrl">The CSS URL</param>
        /// <returns>URL of the Logo image</returns>
        private static string GetImageUrl(string cssUrl)
        {
            int lastLineIndx = cssUrl.LastIndexOf("/", StringComparison.InvariantCultureIgnoreCase);
            string siteURL = cssUrl.Substring(0, lastLineIndx);

            Stream cssStream = GetResponse(cssUrl);

            string str = "";
            using (StreamReader sr = new StreamReader(cssStream))
            {
                //Read the CSS file in the string.
                str = sr.ReadToEnd();

                //Locate page-header section in CSS file.
                int pos = str.LastIndexOf(".page-header", StringComparison.InvariantCultureIgnoreCase);

                //Locate URL in the page-header section of CSS file.
                int p = str.IndexOf("url", pos, StringComparison.InvariantCultureIgnoreCase);

                int beginBr = str.IndexOf("(", p, StringComparison.InvariantCultureIgnoreCase);
                int endBr = str.IndexOf(")", beginBr, StringComparison.InvariantCultureIgnoreCase);

                int urlLn = endBr - beginBr;

                //Get the relative path of image URL enclosed in brackets.
                string imgUrl = str.Substring(beginBr + 1, urlLn - 1);

                if (imgUrl.StartsWith("http", StringComparison.InvariantCultureIgnoreCase))
                    return imgUrl;
 
                int count = 0;
                while (imgUrl.IndexOf("../", StringComparison.InvariantCultureIgnoreCase) != -1)
                {
                    imgUrl = imgUrl.Remove(imgUrl.IndexOf("../", StringComparison.InvariantCultureIgnoreCase), 3);
                    count = count + 1;
                }

                while (count >= 1)
                {
                    siteURL = siteURL.Remove(siteURL.LastIndexOf("/", StringComparison.InvariantCulture));
                    count--;
                }

                return (siteURL + "/" + imgUrl);
            }
        }


        #region IDisposable Members

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                timer.Change(Timeout.Infinite, Timeout.Infinite);
                timer.Dispose();
                web.Dispose();
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}
